package com.icesoft.wechat.utils.http;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@SuppressWarnings("unused")
@Slf4j
public class FastRestTemplate {

	private String url;
	private final HttpHeaders headers = new HttpHeaders();
	private String body;
	private MultiValueMap<String, String> params;
	private RestTemplate restTemplate;

	protected FastRestTemplate(String url, String body) {
		this.url = url;
		this.body = body;
	}

	protected FastRestTemplate(String url, MultiValueMap<String, String> params) {
		this.url = url;
		this.params = params;
	}

	protected FastRestTemplate(String url) {
		this.url = url;
		this.params = new LinkedMultiValueMap<>();
	}

	/**
	 * 使用body数据进行请求，不要使用addParam方法设置请求参数, APPLICATION_JSON_UTF8
	 */
	public static FastRestTemplate builder(String url, String body) {
		return new FastRestTemplate(url, body).contentType(MediaType.APPLICATION_JSON_UTF8);
	}

	/**
	 * 使用map参数进行请求
	 */
	public static FastRestTemplate builder(String url) {
		return new FastRestTemplate(url);
	}

	/**
	 * 使用map参数进行请求
	 */
	public static FastRestTemplate builder(String url, Map<String, String> params) {
		MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
		for (Map.Entry<String, String> entry : params.entrySet()) {
			map.add(entry.getKey(), entry.getValue());
		}
		return new FastRestTemplate(url, map);
	}

	/**
	 * 使用map参数进行请求
	 */
	public static FastRestTemplate builder(String url, MultiValueMap<String, String> params) {
		return new FastRestTemplate(url, params);
	}

	public FastRestTemplate addHeader(String headerName, String headerValue) {
		headers.add(headerName, headerValue);
		return this;
	}

	public FastRestTemplate addHeaders(Map<String, String> map) {
		map.forEach((key, value) -> {
			headers.add(key, value);
		});
		return this;
	}

	public FastRestTemplate contentType(MediaType mediaType) {
		headers.setContentType(mediaType);
		return this;
	}

	public FastRestTemplate addParam(String name, String value) {
		params.add(name, value);
		return this;
	}

	public FastRestTemplate addParams(Map<String, String> map) {
		map.forEach((key, value) -> {
			params.add(key, value);
		});
		return this;
	}

	public FastRestTemplate restTemplate(RestTemplate restTemplate) {
		this.restTemplate = restTemplate;
		return this;
	}

	public String get() {
		return get(String.class);
	}

	public <T> T get(Class<T> responseType) {
		return http(responseType, HttpMethod.GET).getBody();
	}

	public <T> T get(ParameterizedTypeReference<T> responseType) {
		return http(responseType, HttpMethod.GET).getBody();
	}

	public String post() {
		return post(String.class);
	}

	public <T> T post(ParameterizedTypeReference<T> responseType) {
		return http(responseType, HttpMethod.POST).getBody();
	}

	public <T> T post(Class<T> responseType) {
		return http(responseType, HttpMethod.POST).getBody();
	}

	public <T> ResponseEntity<T> http(Class<T> responseType, HttpMethod httpMethod) {
		return http(responseType, null, httpMethod);
	}

	public <T> ResponseEntity<T> http(ParameterizedTypeReference<T> responseType, HttpMethod httpMethod) {
		return http(null, responseType, httpMethod);
	}

	private <T> ResponseEntity<T> http(Class<T> responseType1, ParameterizedTypeReference<T> responseType2,
									   HttpMethod httpMethod) {
		if (restTemplate == null) {
			restTemplate = RestTemplateConfiguration.DEFAULT_REST_TEMPLATE;
		}
		if (headers.getContentType() == null) {
			contentType(MediaType.APPLICATION_FORM_URLENCODED);
		}
		headers.add("x-requested-with", "XMLHttpRequest");
		ResponseEntity<T> responseEntity;
		List<String> uriVariables = new ArrayList<>();
		if (httpMethod == HttpMethod.GET) {
			if (!url.contains("?")) {
				url = url + "?";
			}
			params.forEach((name, values) -> {
				for (String value : values) {
					url = url + "&" + name + "={" + name + "}";
					uriVariables.add(value);
				}
			});
		}
		if (body != null) {
			log.trace("请求url:{}，请求body：{}", url, body);
			log.trace("请求headers:{}，请求httpMethod：{}", headers, httpMethod);
			HttpEntity<String> bodyEntity = new HttpEntity<>(body, headers);
			if (responseType1 != null) {
				responseEntity = restTemplate.exchange(url, httpMethod, bodyEntity, responseType1,
						uriVariables.toArray());
			} else {
				responseEntity = restTemplate.exchange(url, httpMethod, bodyEntity, responseType2,
						uriVariables.toArray());
			}
		} else {
			log.debug("请求url:{}，请求params：{}", url, params);
			log.debug("请求headers:{}，请求httpMethod：{}", headers, httpMethod);
			HttpEntity<MultiValueMap<String, String>> paramsEntity = new HttpEntity<>(params, headers);
			if (responseType1 != null) {
				responseEntity = restTemplate.exchange(url, httpMethod, paramsEntity, responseType1,
						uriVariables.toArray());
			} else {
				responseEntity = restTemplate.exchange(url, httpMethod, paramsEntity, responseType2,
						uriVariables.toArray());
			}
		}
		if (log.isDebugEnabled()) {
			log.debug("返回结果：{}", responseEntity);
		}
		return responseEntity;
	}

	@Override
	public String toString() {
		return "url:" + url + "\nheaders:" + headers + "\nbody:" + body + "\nparams:" + params;
	}

	public String getUrl() {
		return url;
	}

	public HttpHeaders getHeaders() {
		return headers;
	}

	public String getBody() {
		return body;
	}

	public MultiValueMap<String, String> getParams() {
		return params;
	}

}
